/*********************************************************
*  OCUnity Project - A Test C Framework for testing OpenCPU
*  Copyright (c) 2021 China Mobile IOT.
*  created by sushundi 2021-09-24
********************************************************/

#include "octest.h"

#ifndef OCTestPrintf
#error Macro Name of OCTestPrintf is not defined!
#endif

static const char OCTestStrPass[]                   = "PASS";
static const char OCTestStrFail[]                   = "FAIL";
static const char OCTestStrExpected[]               = ", Expected ";
static const char OCTestStrGt[]                     = "> ";
static const char OCTestStrLt[]                     = "< ";
static const char OCTestStrEqual[]                	= "= ";
static const char OCTestStrNotEqual[]               = "!= ";
static const char OCTestStrDelta[]                  = " Within Delta ";
static const char OCTestStrLine[]					= " line ";
static const char OCTestStrColon[]					= ": ";
static const char OCTestStrCalled[]					= " called";
static const char OCTestStrActualEqual[]			= " actual = ";
static const char OCTestStr0x[]						= "0x";
static const char OCTestStrTrue[]					= "TRUE";
static const char OCTestStrFalse[]					= "FALSE";
static const char OCTestStrParentheses[]			= "()";
static const char OCTestStrComma[]				    = ", "; 
static const char OCTestStrVarible[]				= "checked varible: "; 
static const char OCTestStrDot[]				    = ".";
static const char OCTestStrLineFeed[]				= "\n";
static const char OCTestStrCaseCnt[]				= "UnityExpectCaseCnt ";
static const char OCTestStrFailedCnt[]				= "UnityFailedCntOfExpectCase ";
static const char OCTestStrNull[]					= "NULL";
static const char OCTestStrNotNull[]				= "NOT NULL";
static const char OCTestStrReturn[]				    = ", return ";

static OCTEST_UINT32 s_ulOCTestExpectCaseCnt = 0;
static OCTEST_UINT32 s_ulOCTestFailedCntOfExpectCase = 0;
inline void OCTestResetTestCnt(void) {s_ulOCTestExpectCaseCnt = 0; s_ulOCTestFailedCntOfExpectCase = 0;}

inline void OCTestPrintTestCnt(void) 
{
    OCTestPrintf("%s%s%u%s%s",OCTestStrCaseCnt,OCTestStrEqual,s_ulOCTestExpectCaseCnt,OCTestStrComma,OCTestStrFailedCnt);
    OCTestPrintf("%s%u%s%s",OCTestStrEqual,s_ulOCTestFailedCntOfExpectCase,OCTestStrDot,OCTestStrLineFeed);
}

static inline void _IncreaseCntOfExpectCase(void) { ++s_ulOCTestExpectCaseCnt; }

static inline void _IncreaseFailedCounterOfExpectCase(void) { ++s_ulOCTestFailedCntOfExpectCase; }

/*-----------------------------------------------*/
static void OCTestPrintNumberByStyle(const OCTEST_INT32 number, const OCTEST_DISPLAY_STYLE_T style)
{
    if ((style & OCTEST_DISPLAY_RANGE_INT) == OCTEST_DISPLAY_RANGE_INT)
    {
        OCTestPrintf("%d",number);
    }
    else if ((style & OCTEST_DISPLAY_RANGE_UINT) == OCTEST_DISPLAY_RANGE_UINT)
    {
        OCTestPrintf("%u",number);
    }
    else if((style != OCTEST_DISPLAY_STYLE_BOOL) && (style != OCTEST_DISPLAY_STYLE_NULL))
    {
    	OCTestPrintf(OCTestStr0x);
        OCTestPrintf("%x",number);
    }
    else if(style == OCTEST_DISPLAY_STYLE_BOOL)
    {
        OCTestPrintf(number ? OCTestStrTrue : OCTestStrFalse);
    }
    else
    {
        OCTestPrintf(number ? OCTestStrNotNull : OCTestStrNull);
    }
}

/*-----------------------------------------------*/
void OCTestExpectEqualNumber(const OCTEST_INT32 expected,
							const OCTEST_INT32 actual,
							const char *filepath,
							const char *message,
                            OCTEST_MESSAGE_TYPE_E msg_type, 
							const OCTEST_UINT32 lineNumber,
							const OCTEST_DISPLAY_STYLE_T style)
{
    _IncreaseCntOfExpectCase();
    OCTestPrintf("%s%s%u%s",filepath,OCTestStrLine,lineNumber,OCTestStrColon);

    if(((style != OCTEST_DISPLAY_STYLE_BOOL) && (style != OCTEST_DISPLAY_STYLE_NULL) && (expected == actual)) || 
        (((style == OCTEST_DISPLAY_STYLE_BOOL) || (style == OCTEST_DISPLAY_STYLE_NULL)) && (((expected)&&(actual)) || ((!expected)&&(!actual)))))
    {
        OCTestPrintf(OCTestStrPass);
    }
    else
    {
        _IncreaseFailedCounterOfExpectCase();
        OCTestPrintf("%s%s%s",OCTestStrFail,OCTestStrExpected,OCTestStrEqual);
        OCTestPrintNumberByStyle(expected, style);
        OCTestPrintf(OCTestStrActualEqual);
        OCTestPrintNumberByStyle(actual, style);    	
    }
    if(msg_type == OCTEST_MSG_FUNC_CALL)       OCTestPrintf("%s%s%s%s",OCTestStrComma,message,OCTestStrParentheses,OCTestStrCalled);
    else if(msg_type == OCTEST_MSG_VARIABLE)   OCTestPrintf("%s%s%s",OCTestStrComma,OCTestStrVarible,message);
    OCTestPrintf(OCTestStrDot);
    OCTestPrintf(OCTestStrLineFeed);
}					
						 											 
/*-----------------------------------------------*/											 
void OCTestExpectGreaterOrLessOrEqualNumber(const OCTEST_INT32 threshold,
											const OCTEST_INT32 actual,
											const OCTEST_COMPARISON_E compare,
											const char *filepath,
											const char *message,
                                            OCTEST_MESSAGE_TYPE_E msg_type, 
											const OCTEST_UINT32 lineNumber,
											const OCTEST_DISPLAY_STYLE_T style)
{
    int failed = 0;
	_IncreaseCntOfExpectCase();
    
    if(threshold == actual) 
    {
        if(!(compare & OCTEST_EQUAL_TO))   { failed = 1; }   
    }
    else
    {
        if ((style & OCTEST_DISPLAY_RANGE_INT) == OCTEST_DISPLAY_RANGE_INT)
        {
            if ((actual > threshold) && (compare & OCTEST_SMALLER_THAN)) { failed = 1; }
            if ((actual < threshold) && (compare & OCTEST_GREATER_THAN)) { failed = 1; }
        }
        else /* UINT or HEX */
        {
            if (((OCTEST_UINT32)actual > (OCTEST_UINT32)threshold) && (compare & OCTEST_SMALLER_THAN)) { failed = 1; }
            if (((OCTEST_UINT32)actual < (OCTEST_UINT32)threshold) && (compare & OCTEST_GREATER_THAN)) { failed = 1; }
        }
    }
     
	OCTestPrintf("%s%s%u%s",filepath,OCTestStrLine,lineNumber,OCTestStrColon);
    if (failed == 0) /* PASS */
    {
        OCTestPrintf(OCTestStrPass);
    }
	else /* FAIL */
	{
		_IncreaseFailedCounterOfExpectCase();
        OCTestPrintf("%s%s",OCTestStrFail,OCTestStrExpected);
    	if (compare & OCTEST_GREATER_THAN) { OCTestPrintf(OCTestStrGt);       }
    	if (compare & OCTEST_SMALLER_THAN) { OCTestPrintf(OCTestStrLt);       }
    	if (compare & OCTEST_EQUAL_TO)     { OCTestPrintf(OCTestStrEqual);  }
    	if (compare == OCTEST_NOT_EQUAL)   { OCTestPrintf(OCTestStrNotEqual); }
    	OCTestPrintNumberByStyle(threshold, style);
    	OCTestPrintf(OCTestStrActualEqual);
    	OCTestPrintNumberByStyle(actual, style);
    }
    if(msg_type == OCTEST_MSG_FUNC_CALL)       OCTestPrintf("%s%s%s%s",OCTestStrComma,message,OCTestStrParentheses,OCTestStrCalled);
    else if(msg_type == OCTEST_MSG_VARIABLE)   OCTestPrintf("%s%s%s",OCTestStrComma,OCTestStrVarible,message);
    OCTestPrintf(OCTestStrDot);
    OCTestPrintf(OCTestStrLineFeed);  
}		

/*-----------------------------------------------*/																		
void OCTestExpectNumbersWithin(const OCTEST_UINT32 delta,
                            const OCTEST_INT32 expected,
                            const OCTEST_INT32 actual,
							const char *filepath,
							const char *message,
                            OCTEST_MESSAGE_TYPE_E msg_type, 
							const OCTEST_UINT32 lineNumber,
							const OCTEST_DISPLAY_STYLE_T style)
{
    int failed = 0;
	_IncreaseCntOfExpectCase();
	
    if ((style & OCTEST_DISPLAY_RANGE_INT) == OCTEST_DISPLAY_RANGE_INT)
    {
        if (actual > expected)
        {
            failed = (((OCTEST_UINT32)actual - (OCTEST_UINT32)expected) > delta);
        }
        else
        {
            failed = (((OCTEST_UINT32)expected - (OCTEST_UINT32)actual) > delta);
        }
    }
    else
    {
        if ((OCTEST_UINT32)actual > (OCTEST_UINT32)expected)
        {
            failed = (((OCTEST_UINT32)actual - (OCTEST_UINT32)expected) > delta);
        }
        else
        {
            failed = (((OCTEST_UINT32)expected - (OCTEST_UINT32)actual) > delta);
        }
    }
    
    OCTestPrintf("%s%s%u%s",filepath,OCTestStrLine,lineNumber,OCTestStrColon); 
    if(failed == 0) /* PASS */
    {
        OCTestPrintf(OCTestStrPass);
    }
    else /* FAIL */
    {
		_IncreaseFailedCounterOfExpectCase();  
        OCTestPrintf("%s%s",OCTestStrFail,OCTestStrExpected);    
    	OCTestPrintNumberByStyle(expected, style);
    	OCTestPrintf(OCTestStrDelta);
    	OCTestPrintNumberByStyle((OCTEST_INT32)delta, style);
    	OCTestPrintf(OCTestStrActualEqual);
    	OCTestPrintNumberByStyle(actual, style);        
    }	 
    if(msg_type == OCTEST_MSG_FUNC_CALL)       OCTestPrintf("%s%s%s%s",OCTestStrComma,message,OCTestStrParentheses,OCTestStrCalled);
    else if(msg_type == OCTEST_MSG_VARIABLE)   OCTestPrintf("%s%s%s",OCTestStrComma,OCTestStrVarible,message);
    OCTestPrintf(OCTestStrDot);
    OCTestPrintf(OCTestStrLineFeed);   
}

/*-----------------------------------------------*/
void OCTestExecuteFucWithReturn(void * actual,
                                const char *filepath,
                                const char *calledFuncName,
                                const OCTEST_UINT32 lineNumber,
                                const OCTEST_DISPLAY_STYLE_T style,
                                OCTEST_FUC_RETURN_TYPE_E return_type)
{
    OCTestPrintf("%s%s%u%s%s%s%s",filepath,OCTestStrLine,lineNumber,OCTestStrColon,calledFuncName,OCTestStrParentheses,OCTestStrCalled);
    if(return_type != OCTEST_FUC_RETURN_VOID)
    {
        OCTestPrintf("%s",OCTestStrReturn);
        if (return_type == OCTEST_FUC_RETURN_VALUE)         OCTestPrintNumberByStyle((OCTEST_INT32)actual, style);
        else if(return_type == OCTEST_FUC_RETURN_STRING)    OCTestPrintf((char *)actual);
    }
    OCTestPrintf("%s%s",OCTestStrDot, OCTestStrLineFeed);
}	
/*-----------------------------------------------*/		
//UnityExpectNumbersArrayWithin()

/*-----------------------------------------------*/		
//UnityExpectEqualString()
